package file

///
// 静态文件缓存库
// 	这个库只能读取静态文件而无法进行写文件
///
import (
	"fmt"
	"mime"
	"net/http"
	"net/url"
	"path"
	"strings"
	"sync"
	"time"

	httplib ".."
	HTTP "../../http"
	"../../httpdata"
)

// init 初始化
func init() {
	mime.AddExtensionType(".js", "application/x-javascript")
}

// BufferData 缓冲定时器
type BufferData struct {
	Byte *[]byte
	Time int64
}

// Buffer 缓存路由
type Buffer struct {
	// 远程参数
	Path   string // 远程访问路径
	RegExp bool   // 正则匹配
	// 本地参数
	PathLen  int64                 // 路径无用长度
	FilePath string                // 本机文件路径
	Buffer   map[string]BufferData // 缓存队列
	TimeOut  int64                 // 超时
	Size     uint64                // 已用大小(字节)
	MaxSize  uint64                // 缓冲大小(字节)
	// 文件管理器
	FileManagement httplib.FileBuffer
	// 锁
	lock *sync.RWMutex
}

// Routing 返回路由信息
func (B *Buffer) Routing() *HTTP.Routing {
	return &HTTP.Routing{
		Path:   B.Path,
		RegExp: B.RegExp}
}

// ServeHTTP 缓存路由接口
func (B *Buffer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// 获得 url
	strURL, _ := url.PathUnescape(r.URL.String())
	strURL = strURL[B.PathLen:] // 去除无用的映射地址
	// 获得文件类型
	ctype := mime.TypeByExtension(path.Ext(strURL))
	w.Header().Set("Content-Type", ctype)
	// 访问匹配缓存
	B.lock.RLock() // 读
	D, ok := B.Buffer[strURL]
	B.lock.RUnlock() // 解读
	if ok {
		// 更新时间戳
		D.Time = time.Now().Unix()
		// 发送数据
		w.WriteHeader(http.StatusOK)
		w.Write(*D.Byte)
	} else {
		// 保证参数
		path := B.FilePath + strURL
		N := strings.Index(path, "?")
		if N != -1 {
			path = (path)[:N]
		}
		// 判断文件是否存在
		if ok, _ := B.FileManagement.PathExists(path); ok {
			// 打开文件
			f, err := B.FileManagement.Open(path)
			if err != nil {
				HTTP.Log.WarnS(fmt.Sprintf("打开文件失败: %s \n用户请求:%v", B.FilePath+strURL, *r))
				w.WriteHeader(http.StatusNotFound)
				w.Write(httpdata.GetFound(404))
				return
			}
			defer f.Close()
			// 发送数据
			w.WriteHeader(http.StatusOK)
			// 处理数据
			buf := make([]byte, 1024)
			if B.Size < B.MaxSize && B.TimeOut != 0 {
				// 创建缓存
				B.lock.Lock() // 写
				Byte := B.add(strURL)
				for {
					n, _ := f.Read(buf)
					if n == 0 {
						break
					}
					*Byte = append(*Byte, buf[:n]...)
				}
				// 设置大小
				B.Size += uint64(len(*Byte))
				B.lock.Unlock() // 解写
				// 返回数据
				w.Write(*Byte)
			} else {
				for {
					n, _ := f.Read(buf)
					if n == 0 {
						break
					}
					w.Write(buf[:n])
				}
			}
		} else {
			HTTP.Log.WarnS("异常访问: " + path)
			w.WriteHeader(http.StatusNotFound)
			w.Write(httpdata.GetFound(404))
		}
	}

}

// add 添加数据
// path	文件路径
func (B *Buffer) add(path string) *[]byte {
	// 日志
	HTTP.Log.DebugS("添加缓存: " + path)
	// 创建
	B.Buffer[path] = BufferData{
		Byte: new([]byte),
		Time: time.Now().Unix(),
	}
	return B.Buffer[path].Byte
}

// BufferInit 初始化
// 	path 	路径
//	timeOut	超时/S
//	MaxSize 缓存大小
func BufferInit(path string, timeOut int64, MaxSize uint64) (B *Buffer) {
	B = &Buffer{}
	B.FilePath = path
	B.Buffer = make(map[string]BufferData, 0)
	B.TimeOut = timeOut
	B.MaxSize = MaxSize
	B.RegExp = true
	B.lock = new(sync.RWMutex)
	go func() {
		for {
			// 超时
			if B.TimeOut == 0 {
				return
			}
			<-time.After(time.Second * time.Duration(B.TimeOut))
			T := time.Now().Unix()
			B.lock.Lock()
			for key, D := range B.Buffer {
				// 判断超时
				if (T - D.Time) > B.TimeOut {
					HTTP.Log.DebugS("删除缓存: " + key)
					// 设置释放
					B.Size -= uint64(len(*(B.Buffer[key].Byte)))
					// 删除
					delete(B.Buffer, key)
				}
			}
			B.lock.Unlock()
		}
	}()
	return
}
